﻿using System;
using System.Collections.Generic;
using UnityEngine;

public static class RandomUtils
{
    // -------------------- 整型 --------------------
    public static List<int> GetRandomUniqueInts(int count, int min, int max, int? seed = null)
    {
        int total = max - min;
        if (total <= 0)
            throw new ArgumentException("max must be greater than min");
        if (count > total)
            throw new ArgumentException("count exceeds available unique integers");

        List<int> pool = new(total);
        for (int i = min; i < max; i++)
            pool.Add(i);

        Shuffle(pool, seed);
        return pool.GetRange(0, count);
    }

    // -------------------- 浮点 --------------------

    public static List<float> GetRandomUniqueFloats(int count, float min, float max, float step = 0.1f, int? seed = null)
    {
        if (step <= 0f) throw new ArgumentException("step must be positive");
        int total = (int)((max - min) / step);
        if (total <= 0) throw new ArgumentException("Invalid range or step size");
        if (count > total) throw new ArgumentException("count exceeds available float values");

        List<float> pool = new(total);
        for (int i = 0; i < total; i++)
            pool.Add(min + i * step);

        Shuffle(pool, seed);
        return pool.GetRange(0, count);
    }

    public static List<double> GetRandomUniqueDoubles(int count, double min, double max, double step = 0.1, int? seed = null)
    {
        if (step <= 0.0) throw new ArgumentException("step must be positive");
        int total = (int)((max - min) / step);
        if (total <= 0) throw new ArgumentException("Invalid range or step size");
        if (count > total) throw new ArgumentException("count exceeds available double values");

        List<double> pool = new(total);
        for (int i = 0; i < total; i++)
            pool.Add(min + i * step);

        Shuffle(pool, seed);
        return pool.GetRange(0, count);
    }

    // -------------------- Vector2Int / Vector3Int --------------------

    public static List<Vector2Int> GetRandomUniqueVector2Int(int count, int xMin, int xMax, int yMin, int yMax, int? seed = null)
    {
        List<Vector2Int> pool = new();
        for (int x = xMin; x < xMax; x++)
            for (int y = yMin; y < yMax; y++)
                pool.Add(new Vector2Int(x, y));

        if (count > pool.Count)
            throw new ArgumentException("count exceeds total available Vector2Int");

        Shuffle(pool, seed);
        return pool.GetRange(0, count);
    }

    public static List<Vector3Int> GetRandomUniqueVector3Int(int count, int xMin, int xMax, int yMin, int yMax, int zMin, int zMax, int? seed = null)
    {
        List<Vector3Int> pool = new();
        for (int x = xMin; x < xMax; x++)
            for (int y = yMin; y < yMax; y++)
                for (int z = zMin; z < zMax; z++)
                    pool.Add(new Vector3Int(x, y, z));

        if (count > pool.Count)
            throw new ArgumentException("count exceeds total available Vector3Int");

        Shuffle(pool, seed);
        return pool.GetRange(0, count);
    }

    // -------------------- Vector2 / Vector3 (float) --------------------

    public static List<Vector2> GetRandomUniqueVector2(int count, float xMin, float xMax, float yMin, float yMax, float step = 0.1f, int? seed = null)
    {
        List<Vector2> pool = new();
        for (float x = xMin; x < xMax; x += step)
            for (float y = yMin; y < yMax; y += step)
                pool.Add(new Vector2(x, y));

        if (count > pool.Count)
            throw new ArgumentException("count exceeds total available Vector2");

        Shuffle(pool, seed);
        return pool.GetRange(0, count);
    }

    public static List<Vector3> GetRandomUniqueVector3(int count, float xMin, float xMax, float yMin, float yMax, float zMin, float zMax, float step = 0.1f, int? seed = null)
    {
        List<Vector3> pool = new();
        for (float x = xMin; x < xMax; x += step)
            for (float y = yMin; y < yMax; y += step)
                for (float z = zMin; z < zMax; z += step)
                    pool.Add(new Vector3(x, y, z));

        if (count > pool.Count)
            throw new ArgumentException("count exceeds total available Vector3");

        Shuffle(pool, seed);
        return pool.GetRange(0, count);
    }

    // -------------------- 通用洗牌 --------------------

    private static void Shuffle<T>(List<T> list, int? seed)
    {
        System.Random rng = seed.HasValue ? new System.Random(seed.Value) : new System.Random();

        for (int i = list.Count - 1; i > 0; i--)
        {
            int j = rng.Next(0, i + 1);
            (list[i], list[j]) = (list[j], list[i]);
        }
    }
}
